﻿//统一文件为utf-8编码编译
#pragma execution_character_set("utf-8")
///////////////////////////////////////////////////////////////////////////
// 文件名:     qtcpsocketserver.cpp
// 描述:
// 作者:      颜磊
// 创建时间:   2024-06-08 23:45
///////////////////////////////////////////////////////////////////////////
#include "qtcpsocketserver.h"
#include "networkstruct.h"

QTcpSocketServer::QTcpSocketServer(QString m_address,uint16_t m_listenPort,QObject *parent) : QThread(parent)
{
    moveToThread(this);
    address = m_address;
    listenPort = m_listenPort;
    connectionId = 0;
    isOpen = false;
    connect(this,&QTcpSocketServer::signal_openSocket,this,&QTcpSocketServer::slot_openSocket);
    connect(this,&QTcpSocketServer::signal_closeSocket,this,&QTcpSocketServer::slot_closeSocket);

    listenTimer.setInterval(3000);
    connect(&listenTimer,&QTimer::timeout,this,&QTcpSocketServer::slot_openListen);//多次监听
    start();
}

QTcpSocketServer::~QTcpSocketServer()
{
    for(QMap<uint64_t,QTcpSocketConnection*>::iterator it = connectionMap.begin();it !=connectionMap.end();it++){
        QTcpSocketConnection *tcpSocketConnection = connectionMap.take(it.key());
        tcpSocketConnection->close();
        delete tcpSocketConnection;
    }
    quit();
    wait();
}

void QTcpSocketServer::open()
{
    signal_openSocket();
}

void QTcpSocketServer::close()
{
    signal_closeSocket();
}

void QTcpSocketServer::slot_sendData(uint64_t connectionId, QByteArray data)
{
    for(QMap<uint64_t,QTcpSocketConnection*>::iterator it = connectionMap.begin();it !=connectionMap.end();it++){
        if(it.key() == connectionId || connectionId==0){
            it.value()->sendData(data);
        }
    }
}

void QTcpSocketServer::slot_exitConnection(uint64_t connectionId)
{
    QTcpSocketConnection *socketConnection = connectionMap.take(connectionId);
    if(socketConnection != nullptr){
        socketConnection->close();
        delete socketConnection;
    }
}

void QTcpSocketServer::slot_joinConnection(qintptr handle)
{
    int newConnectionId = getConnectionId();
    QTcpSocketConnection *tcpSocketConnection= new QTcpSocketConnection(newConnectionId,handle);
    connect(tcpSocketConnection,&QTcpSocketConnection::signal_recvData,this,&QTcpSocketServer::signal_recvData);
    connect(tcpSocketConnection,&QTcpSocketConnection::signal_exitConnection,this,&QTcpSocketServer::slot_exitConnection);
    tcpSocketConnection->open();
    connectionMap.insert(newConnectionId,tcpSocketConnection);
    signal_joinConnection(newConnectionId);
}

void QTcpSocketServer::slot_openSocket()
{
    if(!isOpen){
        tcpSocketListen = new QTcpSocketListen(this);
        connect(tcpSocketListen,&QTcpSocketListen::signal_incomingConnection,this,&QTcpSocketServer::slot_joinConnection);//新的连接进来
        slot_openListen();
    }
}

void QTcpSocketServer::slot_closeSocket()
{
    if(isOpen){
        slot_closeListen();
        delete tcpSocketListen;
    }
}

void QTcpSocketServer::slot_openListen()
{
    if(tcpSocketListen->isListening()){
        if(listenTimer.isActive()) listenTimer.stop();
    }else{
        QHostAddress hostAddress;
        if(address.isEmpty() || address == "Any"){
            hostAddress=QHostAddress::Any;
        }else{
            hostAddress=QHostAddress(address);
        }
        if(!tcpSocketListen->listen(hostAddress,listenPort)){
            qCritical() << "tcp listen error!" << tcpSocketListen->errorString();
            if(!listenTimer.isActive())
                listenTimer.start();
        }else{
            qInfo() << "tcp listen success!" << "hostAddress:" << hostAddress.toString() << "Port" << QString::number(listenPort);
        }
    }
}

void QTcpSocketServer::slot_closeListen()
{
    if(listenTimer.isActive()) listenTimer.stop();
    if(tcpSocketListen->isListening())
        tcpSocketListen->close();
}

uint64_t QTcpSocketServer::getConnectionId()
{
    return ++connectionId;
}

void QTcpSocketServer::run()
{
    exec();
}
////==========================================TCP监听
///
QTcpSocketListen::QTcpSocketListen(QObject *parent): QTcpServer(parent)
{

}

QTcpSocketListen::~QTcpSocketListen()
{

}

void QTcpSocketListen::incomingConnection(qintptr handle)
{
    signal_incomingConnection(handle);
}

////============================================TCP连接
///
QTcpSocketConnection::QTcpSocketConnection(uint64_t m_connectionId,qintptr m_socketPtr,QObject *parent) : QThread(parent)
{
    qDebug() <<__FUNCTION__ << QString("连接管道创建");
    moveToThread(this);
    connectionId  = m_connectionId;
    socketPtr = m_socketPtr;
    sendPackId = 0;
    nextFrameSerial = 0;
    isOpen = false;
    qRegisterMetaType<uint64_t>("uint64_t");
    qRegisterMetaType<QByteArray>("QByteArray");
    connect(this,&QTcpSocketConnection::signal_sendData,this,&QTcpSocketConnection::slot_sendData);
    connect(this,&QTcpSocketConnection::signal_openSocket,this,&QTcpSocketConnection::slot_openSocket);
    connect(this,&QTcpSocketConnection::signal_closeSocket,this,&QTcpSocketConnection::slot_closeSocket);
    start();
}

QTcpSocketConnection::~QTcpSocketConnection()
{
    qDebug() <<__FUNCTION__ << QString("连接管道销毁");
    quit();
    wait();
}

void QTcpSocketConnection::open()
{
    signal_openSocket();
}

void QTcpSocketConnection::close()
{
    signal_closeSocket();
}

void QTcpSocketConnection::sendData(QByteArray data)
{
    signal_sendData(data);
}

void QTcpSocketConnection::slot_tcpSocketReadyRead()
{
    QByteArray byteArray = tcpSocket->readAll();
    parsingFrameData(byteArray);
}

void QTcpSocketConnection::slot_tcpSocketDisconnected()
{
    emit signal_exitConnection(connectionId);
}

void QTcpSocketConnection::slot_openSocket()
{
    if(!isOpen){
        tcpSocket = new QTcpSocket(nullptr);
        tcpSocket->setSocketDescriptor((qintptr)socketPtr);
        tcpSocket->setReadBufferSize(TCP_SOCKET_FRAME_LEN);
        connect(tcpSocket,&QTcpSocket::readyRead,this,&QTcpSocketConnection::slot_tcpSocketReadyRead,Qt::DirectConnection);
        connect(tcpSocket,&QTcpSocket::disconnected,this,&QTcpSocketConnection::slot_tcpSocketDisconnected,Qt::DirectConnection);
        isOpen = true;
    }
}

void QTcpSocketConnection::slot_closeSocket()
{
    if(isOpen){
        tcpSocket->close();
        delete tcpSocket;
        isOpen = false;
    }
}

void QTcpSocketConnection::slot_sendData(QByteArray byteArray)
{
    QByteArray sendByteArray;
    sendByteArray.resize(TCP_SOCKET_FRAME_LEN);
    int sendDataLen = TCP_SOCKET_FRAME_LEN - sizeof(SocketFrameHeader);
    SocketFrameHeader socketFrameHeader;
    socketFrameHeader.packId = getSendPackId();
    socketFrameHeader.packLen = byteArray.size();
    socketFrameHeader.frameSerial = 0;//帧序号

    while(byteArray.size() > 0){
        socketFrameHeader.dataLen = byteArray.size() > sendDataLen ? sendDataLen : byteArray.size();
        if(byteArray.size() <= sendDataLen){
            socketFrameHeader.frameMark = FRAME_MARK_END;
        }else{
            socketFrameHeader.frameMark = FRAME_MARK_CENTER;
        }
        memcpy(sendByteArray.data(),&socketFrameHeader,sizeof(SocketFrameHeader));
        memcpy(sendByteArray.data() + sizeof(SocketFrameHeader),byteArray.data(),byteArray.size() > sendDataLen ? sendDataLen : byteArray.size());
        tcpSocket->write(sendByteArray);
        byteArray.remove(0,byteArray.size() > sendDataLen ? sendDataLen : byteArray.size());
        socketFrameHeader.frameSerial++;
        QThread::msleep(1);
    }
}

quint16 QTcpSocketConnection::getSendPackId()
{
    quint16 nowId = sendPackId;
    sendPackId++;
    return nowId;
}

void QTcpSocketConnection::parsingFrameData(const QByteArray &byteArray)
{
    recvFrameTempData.append(byteArray);
    while(recvFrameTempData.size() >= TCP_SOCKET_FRAME_LEN){
        SocketFrameHeader socketFrameHeader;
        if(recvFrameTempData.size() < sizeof (socketFrameHeader)){
            qCritical() << __FUNCTION__ << "The frame data is less than the frame header length.";
            //return;
        }
        memcpy(&socketFrameHeader,recvFrameTempData,sizeof (socketFrameHeader));

        if(socketFrameHeader.syncMark != TCP_SYNC_MARK){
            qCritical() << __FUNCTION__ << "Sync mark error in frame header.";
            //return;
        }

        if(socketFrameHeader.packId != recvPackId){
            recvPackData.clear();
            recvPackId = socketFrameHeader.packId;
        }

        if(socketFrameHeader.frameSerial != nextFrameSerial){
            qCritical() << __FUNCTION__ << "The frame number does not match.";
            //return;
        }

        nextFrameSerial++;

        QByteArray frameData;
        frameData.resize(socketFrameHeader.dataLen);
        memcpy(frameData.data(),recvFrameTempData.data()+sizeof (socketFrameHeader),socketFrameHeader.dataLen);
        recvPackData.append(frameData);


        if(socketFrameHeader.frameMark == FRAME_MARK_END){
            if(socketFrameHeader.packLen != recvPackData.size()){
                qCritical() << __FUNCTION__ << "The packet length does not match.";
                return;
            }else{
                //start dispose pack data
                emit signal_recvData(connectionId,recvPackData);
            }
            nextFrameSerial = 0;
            recvPackData.clear();
        }
        recvFrameTempData.remove(0,TCP_SOCKET_FRAME_LEN);
    }
}

void QTcpSocketConnection::run()
{
    exec();
}


